#include "EquationSolver.hpp"
#include <iostream>

using namespace std; 

const double Pi = acos(-1.) ;
class F1 : public Function{
public:
    double operator() (double x) const{
        return 1.0/x-tan(x);
    }
    double derivative(double x) const{
        return -1.0/(pow(x,2))-1/(pow(cos(x),2));
    }
}f1;

class F2 : public Function{
public:
    double operator() (double x) const{
        return 1.0/x-pow(2,x);
    }
    double derivative(double x) const{
        return -1.0/(pow(x,2))-pow(2,x)*log(2);
    }
}f2;

class F3 : public Function{
public:
    double operator() (double x) const{
        return pow(2,-x)+pow(M_E,x)+2*cos(x)-6;
    }
    double derivative(double x) const{
        return -log(2)*pow(2,-x)+pow(M_E,x)-2*sin(x)-6;
    }
}f3;

class F4 : public Function{
public:
    double operator() (double x) const{
        return (pow(x,3)+4*x*x+3*x+5)/(2*pow(x,3)-9*x*x+18*x-2);
    }
    double derivative(double x) const{
        return ((3*x*x+8*x+3)*(2*pow(x,3)-9*x*x+18*x-2)-(pow(x,3)+4*x*x+3*x+5)*(6*x*x-18*x+18))/pow((2*pow(x,3)-9*x*x+18*x-2),2);
    }
}f4;

void solve_f1() {
    cout << "Solving 1/x-tan(x) on [0,pi/2]" << endl;
    Bisection_Method solver_f1(F1(),0,Pi/2);
    double x = solver_f1.solve();
    cout << "A root is :" << x << endl;
    cout << "Error is :" << f1(x) << endl;
}

void solve_f2() {
    cout << "Solving 1/x-2^x on [0,1]" << endl;
    Bisection_Method solver_f2(F2(),0,1);
    double x = solver_f2.solve();
    cout << "A root is :" << x << endl;
    cout << "Error is :" << f2(x) << endl;
}

void solve_f3() {
    cout << "Solving 2^(-x)+e^x+2cosx-6 on [1,3]" << endl;
    Bisection_Method solver_f3(F3(),0,3);
    double x = solver_f3.solve();
    cout << "A root is :" << x << endl;
    cout << "Error is :" << f3(x) << endl;
}

void solve_f4() {
    cout << "Solving (pow(x,3)+4*x*x+3*x+5)/(2*pow(x,3)-9*x*x+18*x-2) on [0,4]" << endl;
    Bisection_Method solver_f4(F4(),0,4);
    double x = solver_f4.solve();
    cout << "A root is :" << x << endl;
    cout << "Error is :" << f4(x) << endl;
}

int main() {
    solve_f1();
    solve_f2();
    solve_f3();
    solve_f4();
    return 0;
}